package com.meichuang.meipian.video.decode;

import android.graphics.SurfaceTexture;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.view.Surface;

import com.meichuang.meipian.video.log.LogUtil;

import java.nio.ByteBuffer;
import java.util.HashMap;

/**
 * Created by wanglvbo on 2019/3/6.
 */

public class MediaCodecDecode {
    public static boolean isSettingOpenMediaCodec = true;
    public static boolean isOpenMediaCodec = true;
    public static int idthis = -1;
    public static HashMap<Long,MediaCodecDecode> mapMedia = new HashMap<Long,MediaCodecDecode>();
    public MediaCodecDecode(){
        idthis++;
        thisidadd = idthis;
        LogUtil.w("MediaCodecDecode MediaCodecDecode new  id= "+idthis);
    }
    /**
     * 准备
     *
     */
//    private native void enginePrepared(long avMediaReaderAdd);
    /**
     * 播放文件路径
     */
    private String dataSource;
    /**
     * 硬解码mime
     */
    private MediaFormat mediaFormat;
    /**
     * 视频硬解码器
     */
    private MediaCodec mediaCodec;
    /**
     * 渲染surface
     */
    /**
     * 视频解码器info
     */
    private int thisidadd = -1;
    private MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
    private Surface surface;
    private SurfaceTexture surfaceTexture;
    private boolean isupdateTextureOk = false;
//    private int onFrameAvailableCount = 0;
    public int mediacodecInit(long avMediaReaderId,int textureid_mediacodec,int mimetype, int width, int height, byte[] csd0, byte[] csd1)
    {

        LogUtil.w("MediaCodecDecode textureid_mediacodec "+textureid_mediacodec);
        if(!isSettingOpenMediaCodec){//如果从设置里面关闭了硬解
            return -1;
        }
        if(!isOpenMediaCodec){//如果关掉了硬解 内部逻辑
            return -1;
        }
        int result = -1;
        if(textureid_mediacodec < 0){
            return result;
        }
        if(surface == null){
            surfaceTexture = new SurfaceTexture(textureid_mediacodec);
            surfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
                @Override
                public void onFrameAvailable(SurfaceTexture surfaceTexture) {
                    isupdateTextureOk = true;
//                    onFrameAvailableCount++;
                }
            });
            surface = new Surface(surfaceTexture);
        }

        if(surface != null)
        {
            try {
                String mtype = getMimeType(mimetype);//"video/avc";//
                mediaFormat = MediaFormat.createVideoFormat(mtype, width, height);
                mediaFormat.setInteger(MediaFormat.KEY_WIDTH, width);
                mediaFormat.setInteger(MediaFormat.KEY_HEIGHT, height);
                int maxPixels = ((width + 15) / 16) * ((height + 15) / 16) * 16 * 16;
//                int minCompressionRatio = 2;

//                int maxInputSize = (maxPixels * 3) / (2 * minCompressionRatio);
                mediaFormat.setInteger(android.media.MediaFormat.KEY_MAX_INPUT_SIZE, maxPixels);
//                mediaFormat.setLong(MediaFormat.KEY_MAX_INPUT_SIZE, width * height);
                mediaFormat.setInteger(android.media.MediaFormat.KEY_MAX_INPUT_SIZE, 0);
                mediaFormat.setByteBuffer("csd-0", ByteBuffer.wrap(csd0));
                mediaFormat.setByteBuffer("csd-1", ByteBuffer.wrap(csd1));
                LogUtil.w(" mediaFormat "+ mediaFormat.toString());
                mediaCodec = MediaCodec.createDecoderByType(mtype);
                if(surface != null)
                {
                    mediaCodec.configure(mediaFormat, surface, null, 0);
                    mediaCodec.start();
                }
                result = 1;
            } catch (Exception e) {
                result = -1;
                e.printStackTrace();
            }
            if(result != 1){
                stop();
            }else{
                mapMedia.put(Long.valueOf(avMediaReaderId),this);
            }
        }
        return result;
    }
//    private int dataIndex = -1;
    private int havavideoCount = 0;
    private int pakageCount = 0;
    private boolean isfristNoDate = true;
    public int mediacodecDecode(byte[] bytes, int size, int pts)
    {
        if(size == 4){
        }else{
            pakageCount++;
        }
        int result = 0;
        isupdateTextureOk = false;
        boolean isWaitTextureUpdate = true;//是否需要等待
        if(bytes != null && mediaCodec != null && info != null)
        {
            try
            {
                if(size == 4){
                    if(isfristNoDate){
                        isfristNoDate = false;
                        int inputBufferIndex = mediaCodec.dequeueInputBuffer(10000);

                        while(inputBufferIndex<0){
                            Thread.sleep(50);
                            inputBufferIndex = mediaCodec.dequeueInputBuffer(10000);
                        }
                        if(inputBufferIndex >= 0)
                        {
                            mediaCodec.queueInputBuffer(
                                    inputBufferIndex, 0, 0, -1, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                        }
                    }

                }else{
                    int inputBufferIndex = mediaCodec.dequeueInputBuffer(10000);
                    while(inputBufferIndex<0){
                        inputBufferIndex = mediaCodec.dequeueInputBuffer(10000);
                    }
                    if(inputBufferIndex >= 0)
                    {
                        ByteBuffer byteBuffer = mediaCodec.getInputBuffers()[inputBufferIndex];
                        byteBuffer.clear();
                        byteBuffer.put(bytes);
                        mediaCodec.queueInputBuffer(inputBufferIndex, 0, size, pts, 0);
                  }
                }

                int index = mediaCodec.dequeueOutputBuffer(info, 10000);
                if(index < 0){
                    result = 1;
                }else{
                    result = 0;
                }
                if(index>0){
                    havavideoCount++;
                    isupdateTextureOk = false;
                    updateRender();
                    mediaCodec.releaseOutputBuffer(index, true);
                    long startTime = System.currentTimeMillis();
                    while (!isupdateTextureOk && pakageCount >= havavideoCount) {
                        updateRender();
                        if(System.currentTimeMillis() - startTime>8){
//                            LogUtil.w("MediaCodecDecode dithis"+thisidadd+ "  "+"  updateRender end while time "+havavideoCount);
                            break;
                        }
                    }
                    updateRender();
                }
            }catch (Exception e)
            {
                e.printStackTrace();
            }
        }
        return result;
    }

    public void updateRender(){//更新纹理
        surfaceTexture.updateTexImage();
    }
    private String getMimeType(int type)
    {
        if(type == 1)
        {
            return "video/avc";
        }
        else if(type == 2)
        {
            return "video/hevc";
        }
        else if(type == 3)
        {
            return "video/mp4v-es";
        }
        else if(type == 4)
        {
            return "video/x-ms-wmv";
        }
        return "";
    }
    public void stop()
    {
        if(mediaCodec != null)
        {
            try
            {
                mediaCodec.flush();
                mediaCodec.stop();
                mediaCodec.release();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            mediaCodec = null;
            mediaFormat = null;
        }
        if(surface != null)
        {
            try
            {
                surface.release();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            surface = null;
        }
        if(surfaceTexture != null){

            try
            {
                surfaceTexture.release();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            surfaceTexture = null;
        }
    }
}
